using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace RTMP.SimpleClient.Tests.MockServer
{
    /// <summary>
    /// RTMP 握手处理器
    /// </summary>
    public static class HandshakeHandler
    {
        /// <summary>
        /// RTMP协议版本
        /// </summary>
        public const byte RTMP_VERSION = 0x03;

        /// <summary>
        /// 握手包大小 (除了版本字节)
        /// </summary>
        public const int HANDSHAKE_SIZE = 1536;

        /// <summary>
        /// 执行RTMP服务器端握手
        /// </summary>
        /// <param name="stream">客户端网络流</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>握手任务</returns>
        public static async Task PerformServerHandshakeAsync(NetworkStream stream, CancellationToken cancellationToken = default)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));

            Console.WriteLine($"[HandshakeHandler] 开始服务器端RTMP握手");

            try
            {
                // 步骤1: 读取客户端的C0 (1字节版本号)
                var c0 = await ReadBytesAsync(stream, 1, cancellationToken);
                var clientVersion = c0[0];
                Console.WriteLine($"[HandshakeHandler] 收到C0, 客户端版本: 0x{clientVersion:X2}");

                if (clientVersion != RTMP_VERSION)
                {
                    throw new InvalidOperationException($"不支持的RTMP版本: 0x{clientVersion:X2}, 期望版本: 0x{RTMP_VERSION:X2}");
                }

                // 步骤2: 发送S0 (服务器版本)
                await stream.WriteAsync(new byte[] { RTMP_VERSION }, 0, 1, cancellationToken);
                Console.WriteLine($"[HandshakeHandler] 发送S0, 服务器版本: 0x{RTMP_VERSION:X2}");

                // 步骤3: 读取客户端的C1 (1536字节)
                var c1 = await ReadBytesAsync(stream, HANDSHAKE_SIZE, cancellationToken);
                Console.WriteLine($"[HandshakeHandler] 收到C1: {c1.Length}字节");

                // 从C1中提取客户端时间戳和随机数据
                var clientTimestamp = ExtractTimestamp(c1);
                var clientRandomData = ExtractRandomData(c1);
                Console.WriteLine($"[HandshakeHandler] C1客户端时间戳: {clientTimestamp}, 随机数据: {clientRandomData.Length}字节");

                // 步骤4: 生成并发送S1 (服务器的1536字节响应)
                var s1 = GenerateS1(clientTimestamp, clientRandomData);
                await stream.WriteAsync(s1, 0, s1.Length, cancellationToken);
                Console.WriteLine($"[HandshakeHandler] 发送S1: {s1.Length}字节");

                // 步骤5: 发送S2 (回显C1)
                var s2 = GenerateS2(c1);
                await stream.WriteAsync(s2, 0, s2.Length, cancellationToken);
                Console.WriteLine($"[HandshakeHandler] 发送S2: {s2.Length}字节");

                // 步骤6: 读取客户端的C2 (客户端对S1的回应)
                var c2 = await ReadBytesAsync(stream, HANDSHAKE_SIZE, cancellationToken);
                Console.WriteLine($"[HandshakeHandler] 收到C2: {c2.Length}字节");

                // 可选：验证C2的内容
                if (!ValidateC2(s1, c2))
                {
                    Console.WriteLine($"[HandshakeHandler] 警告: C2验证失败，但继续处理");
                }

                Console.WriteLine($"[HandshakeHandler] RTMP握手完成");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[HandshakeHandler] 握手失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 安全读取指定字节数的数据
        /// </summary>
        /// <param name="stream">网络流</param>
        /// <param name="count">要读取的字节数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>读取的字节数组</returns>
        private static async Task<byte[]> ReadBytesAsync(NetworkStream stream, int count, CancellationToken cancellationToken)
        {
            var buffer = new byte[count];
            int totalRead = 0;

            while (totalRead < count)
            {
                int bytesRead = await stream.ReadAsync(buffer, totalRead, count - totalRead, cancellationToken);
                if (bytesRead == 0)
                {
                    throw new EndOfStreamException($"连接意外关闭，期望读取 {count} 字节，实际读取 {totalRead} 字节");
                }
                totalRead += bytesRead;
            }

            return buffer;
        }

        /// <summary>
        /// 从握手包中提取时间戳 (前4字节)
        /// </summary>
        /// <param name="handshakeData">握手数据</param>
        /// <returns>时间戳</returns>
        private static uint ExtractTimestamp(byte[] handshakeData)
        {
            if (handshakeData.Length < 4)
                return 0;

            return BitConverter.ToUInt32(new byte[] { handshakeData[3], handshakeData[2], handshakeData[1], handshakeData[0] }, 0);
        }

        /// <summary>
        /// 从握手包中提取随机数据 (8字节之后的1528字节)
        /// </summary>
        /// <param name="handshakeData">握手数据</param>
        /// <returns>随机数据</returns>
        private static byte[] ExtractRandomData(byte[] handshakeData)
        {
            if (handshakeData.Length < 8)
                return Array.Empty<byte>();

            const int randomDataStart = 8;
            int randomDataLength = Math.Max(0, handshakeData.Length - randomDataStart);
            var randomData = new byte[randomDataLength];
            Array.Copy(handshakeData, randomDataStart, randomData, 0, randomDataLength);
            return randomData;
        }

        /// <summary>
        /// 生成S1握手包
        /// </summary>
        /// <param name="clientTimestamp">客户端时间戳</param>
        /// <param name="clientRandomData">客户端随机数据</param>
        /// <returns>S1数据包</returns>
        private static byte[] GenerateS1(uint clientTimestamp, byte[] clientRandomData)
        {
            var s1 = new byte[HANDSHAKE_SIZE];

            // 前4字节: 服务器时间戳
            var serverTimestamp = (uint)(Environment.TickCount & 0x7FFFFFFF);
            var timestampBytes = BitConverter.GetBytes(serverTimestamp);
            if (BitConverter.IsLittleEndian)
            {
                // 转换为大端序
                Array.Reverse(timestampBytes);
            }
            Array.Copy(timestampBytes, 0, s1, 0, 4);

            // 5-8字节: 填零 (Flash Player版本)
            Array.Clear(s1, 4, 4);

            // 9-1536字节: 回显客户端的随机数据
            if (clientRandomData.Length > 0)
            {
                int copyLength = Math.Min(clientRandomData.Length, HANDSHAKE_SIZE - 8);
                Array.Copy(clientRandomData, 0, s1, 8, copyLength);
            }

            return s1;
        }

        /// <summary>
        /// 生成S2握手包 (直接回显C1)
        /// </summary>
        /// <param name="c1">客户端的C1数据</param>
        /// <returns>S2数据包</returns>
        private static byte[] GenerateS2(byte[] c1)
        {
            var s2 = new byte[HANDSHAKE_SIZE];
            
            // S2应该回显C1的内容，但可以修改时间戳部分
            Array.Copy(c1, 0, s2, 0, Math.Min(c1.Length, HANDSHAKE_SIZE));

            // 可选：更新时间戳字段 (前4字节)
            var currentTimestamp = (uint)(Environment.TickCount & 0x7FFFFFFF);
            var timestampBytes = BitConverter.GetBytes(currentTimestamp);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }
            Array.Copy(timestampBytes, 0, s2, 0, 4);

            return s2;
        }

        /// <summary>
        /// 验证C2包的内容
        /// </summary>
        /// <param name="s1">发送的S1数据</param>
        /// <param name="c2">收到的C2数据</param>
        /// <returns>验证是否通过</returns>
        private static bool ValidateC2(byte[] s1, byte[] c2)
        {
            if (s1.Length != c2.Length)
            {
                return false;
            }

            // C2应该回显S1的随机数据部分 (8字节之后)
            const int randomDataStart = 8;
            for (int i = randomDataStart; i < s1.Length; i++)
            {
                if (s1[i] != c2[i])
                {
                    return false;
                }
            }

            return true;
        }
    }
}